﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Web.Mvc;
using OperationPlugins.Compositions;
using OperationPlugins.Validators;

namespace OperationPlugins.Mvc.Filters
{
    /// <summary>
    /// This is the base class for validation message router attributes.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class NotificationRouterForAllActionsAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// Gets and sets the notification router.
        /// </summary>
        private static INotificationRouter NotificationRouter { get; set; }

        /// <summary>
        /// Provides the context for the ActionExecuting method of the ActionFilterAttribute class.
        /// </summary>
        protected ActionExecutingContext ActionExecutingContext { get; set; }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            ActionExecutingContext = filterContext;
        }

        /// <summary>
        /// Handle notification messages just after the action method has been executed.
        /// </summary>
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (OperationPluginsContext.Current.ContainsNotifications)
            {
                HandleNotifications(OperationPluginsContext.Current.Notifications);
            }
        }

        /// <summary>
        /// Handle notification messages.
        /// </summary>
        /// <param name="notifications">Notification message</param>
        protected virtual void HandleNotifications(ReadOnlyCollection<ValidationResultMessage> notifications)
        {
            NotificationRouter.ShowOnView(ActionExecutingContext.Controller, notifications);
        }

        /// <summary>
        /// Initialize. 
        /// </summary>
        [Export(typeof(IInitializable))]
        private sealed class Initializer : IInitializable
        {
            void IInitializable.Initialize(InitializationContext context)
            {
                NotificationRouter = context.CompositionContainer.GetPlugin<INotificationRouter>();
            }
        }

        /// <summary>
        /// This is the default notification router that shows notification messages on a view.
        /// </summary>
        [Export(typeof(INotificationRouter))]
        [DefaultPriority]
        private sealed class DefaultNotificationRouter : INotificationRouter
        {
            void INotificationRouter.ShowOnView(ControllerBase controller, ReadOnlyCollection<ValidationResultMessage> notifications)
            {
                const string key = "info";

                var values = new List<string>();

                if (controller.TempData.ContainsKey(key))
                {
                    var existing = controller.TempData[key] as IEnumerable<string>;
                    if (existing != null)
                    {
                        values.AddRange(existing);
                    }
                    controller.TempData.Remove(key);
                }

                List<string> distinct = new List<string>();
                distinct.AddRange(values);
                distinct.AddRange(ValidationResultMessage.ToStrings(notifications));

                string[] messages = distinct.Distinct().ToArray();

                values.Clear();
                values.AddRange(messages);

                controller.TempData.Add(key, values.AsEnumerable());
            }
        }

    }
}
